package classloader;

import java.lang.reflect.Method;

/**
 * 类加载器的双亲委托模型的好处:
 * 1.可以确保Java核心库的类型安全:所有的Java应用都至少会引用java.lang.object类,也就是说在运行期java.lang.object这个类会被加载到Java虚拟机中;
 * 如果这个加载过程是由Java应用自己的类加载器所完成的,那么很可能就会在JVM中存在多个版本的java.lang.object类,
 * 而且这些类之间还是不兼容的,相互不可见的(正是命名空间在发挥着作用);
 * 借助于双亲委托机制,Java核心类库中的类的加载工作都是由启动类加载器来统一完成,从而确保了Java应用所使用的都是同一个版本的Java核心类库,他们之间是相互兼容的。
 * 2.可以确保Java核心类库所提供的类不会被自定义的类所替代。
 * 3.不同的类加载器可以为相同名称(binary name)的类创建额外的命名空间。
 * 相同名称的类可以并存在Java虚拟机中，只需要用不同的类加载器来加载他们即可。
 * 不同类加载器所加载的类之间是不兼容的，这就相当于在Java虚拟机内部创建了一个又一个相互隔离的Java类空间，这类技术在很多框架中都得到了实际应用。
 *
 *
 *
 *
 *
 * =======================================
 * 1.每个类加载器都有自己的命名空间，命名空间由该加载器及所有父加载器所加载的类构成；
 * 2.在同一个命名空间中，不会出现类的完整名字（包括类的包名）相同的两个类；
 * 3.在不同的命名空间中，有可能会出现类的完整名字（包括类的包名）相同的两个类；
 * 4.同一命名空间内的类是互相可见的，非同一命名空间内的类是不可见的；
 * 5.子加载器可以见到父加载器加载的类，父加载器也不能见到子加载器加载的类。
 */
public class MyTest21 {

    public static void main(String[] args) throws Exception {
        MyTest16_1 loader1 = new MyTest16_1("load1");
        loader1.setPath("D:\\code\\class\\");
        MyTest16_1 loader2 = new MyTest16_1("load2");
        loader2.setPath("D:\\code\\class\\");
        Class<?> clazz1 = loader1.loadClass("classloader.MyPerson");
        Class<?> clazz2 = loader2.loadClass("classloader.MyPerson");
        //由于clazz1和clazz2分别有不同的类加载器所加载，所以他们处于不同的名称空间里
        System.out.println(clazz1 == clazz2);//false

        Object object1 = clazz1.newInstance();
        Object object2 = clazz2.newInstance();

        Method method = clazz1.getMethod("setMyPerson", Object.class);
        //此处报错，loader1和loader2所处不用的命名空间
        method.invoke(object1, object2);

/*  将MyPerson.class 移动到D:\code\class\ =====》》 后运行
       输出结果：
findClass,输出这句话说明我们自己的类加载器加载了指定的类
class loader name :load1
loadClassData  我们自定义的loadClassData读取class文件字节数组
findClass,输出这句话说明我们自己的类加载器加载了指定的类
class loader name :load2
loadClassData  我们自定义的loadClassData读取class文件字节数组
false
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at classloader.MyTest21.main(MyTest21.java:29)
Caused by: java.lang.ClassCastException: classloader.MyPerson cannot be cast to classloader.MyPerson
	at classloader.MyPerson.setMyPerson(MyPerson.java:8)
	... 5 more

*/
    }
}
